const rp = require("request-promise-native")
const { readFile, writeFile } = require("fs")

const config = require("../config")
const api = require("../libs/api")
const menu = require("./menu")
const { readFileAsync, writeFileAsync } = require("../libs/utils")

class WeChat {
    constructor() {

    }
    // 获取access_token的方法
    getAccessToken() {
        const { appID, appsecret } = config
        const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`
        // 后端发送请求，我们使用request-promise-native库，这个库依赖于request库
        return new Promise((resolve, reject) => {
            // 使用promise来使函数的返回值为请求的数据
            rp({ method: "GET", url, json: true }).then(res => {
                // 修改过期时间，我们提前五分钟获取
                res.expires_in = Date.now() + (res.expires_in - 5 * 60) * 1000
                resolve(res)
            }).catch(err => {
                reject(err)
            })
        })

    }
    // 获取access_token的方法
    saveAccessToken(access_token) {
        const access_token_str = JSON.stringify(access_token) // 转化为字符串，不然保存的就是[object object]
        // 保存到本地accress_token.txt文件中,因为writeFile是一个异步方法，所以我们返回一个promise
        return new Promise((resolve, reject) => {
            writeFile("accress_token.txt", access_token_str, err => {
                if (!err) {
                    resolve()
                } else {
                    reject(err)
                }
            })
        })

    }
    // 读取access_token的方法
    readAccessToken() {
        return new Promise((resolve, reject) => {
            readFile("accress_token.txt", (err, data) => {
                if (!err) {
                    // 转化为js对象
                    data = data.toString()
                    data = JSON.parse(data)
                    resolve(data)
                } else {
                    reject(err)
                }
            })
        })
    }
    // 验证token是否有效的方法
    isValidToken(data) {
        // data 为读取文件
        if (!data || !data.access_token || !data.expires_in) return false
        return data.expires_in > Date.now()
    }

    fetchAccessToken() {
        // 获取一次后，如果有直接返回
        if (this.access_token && this.expires_in && this.isValidToken(this)) {
            return Promise.resolve({ access_token: this.access_token, expires_in: this.expires_in })
        }

        return this.readAccessToken()
            .then(async res => {
                // 判断是否过期
                if (this.isValidToken(res)) {
                    // 没有过期直接返回
                    return Promise.resolve(res)
                } else {
                    // 过期调用接口请求
                    const data = await this.getAccessToken()
                    // 保存
                    this.saveAccessToken(data)
                    // 返回
                    return Promise.resolve(data)
                }
            })
            .catch(async err => {
                // 本地文件没有保存
                const data = await this.getAccessToken()
                // 保存
                this.saveAccessToken(data)
                // 返回
                return Promise.resolve(data)
            })
            .then(res => {
                // 这里主要是将相关信息放到实例对象上
                const { expires_in, access_token } = res
                this.expires_in = expires_in
                this.access_token = access_token
                return Promise.resolve(res)
            })
    }

    createMenu(body) {
        // 创建菜单
        return new Promise(async (resolve, reject) => {
            try {
                const { access_token } = await this.fetchAccessToken()
                const url = `${api.menu.create}access_token=${access_token}`
                const res = await rp({ method: "POST", json: true, url, body }) // 请求数据
                resolve(res)
            } catch (error) {
                reject(`createMenu方法处理问题${error}`);
            }
        })
    }

    deleteMenu() {
        return new Promise(async (resolve, reject) => {
            try {
                const { access_token } = await this.fetchAccessToken()
                const url = `${api.menu.delete}access_token=${access_token}`
                const res = rp({ method: "GET", json: true, url })
                resolve(res)
            } catch (error) {
                reject(`deleteMenu方法处理问题${error}`)
            }
        })
    }

    // 获取jsapi_ticket的方法
    getTicket() {
        // 因为需要异步获取，这里返回promise
        return new Promise(async(resolve,reject) => {
            const data = await this.fetchAccessToken()
            console.log("data",data);
            const url = `${api.ticket}&access_token=${data.access_token}`
            console.log(url)
            rp({ method: "GET", url, json: true }).then(res => {
                // 格式化
                const {ticket,expires_in} = res
                console.log(res)
                resolve({
                    ticket,
                    ticket_expires_in:Date.now() + (expires_in -300) * 1000
                })
            }).catch(err => {
                reject(err)
            })

        })

    }
    // 保存jsapi_ticket的方法
    saveTicket(ticket) {
        return writeFileAsync(ticket,"./ticket.txt")
    }
    // 读取access_token的方法
    readTicket() {
        return readFileAsync("./ticket.txt")
    }
    // 验证token是否有效的方法
    isValidTicket(data) {
        // data 为读取文件
        if (!data || !data.ticket || !data.ticket_expires_in) return false
        return data.ticket_expires_in > Date.now()
    }

    fetchTicket() {
        // 获取一次后，如果有直接返回
        if (this.ticket && this.ticket_expires_in && this.isValidTicket(this)) {
            return Promise.resolve({ ticket: this.ticket, ticket_expires_in: this.ticket_expires_in })
        }

        return this.readTicket()
            .then(async res => {
                // 判断是否过期
                if (this.isValidTicket(res)) {
                    // 没有过期直接返回
                    return Promise.resolve(res)
                } else {
                    // 过期调用接口请求
                    const data = await this.getTicket()
                    // 保存
                    this.saveTicket(data)
                    // 返回
                    return Promise.resolve(data)
                }
            })
            .catch(async err => {
                // 本地文件没有保存
                const data = await this.getTicket()
                // 保存
                this.saveTicket(data)
                // 返回
                return Promise.resolve(data)
            })
            .then(res => {
                // 这里主要是将相关信息放到实例对象上
                const { expires_in, ticket } = res
                this.ticket_expires_in = expires_in
                this.ticket = ticket
                return Promise.resolve(res)
            })
    }
}

// 进行测试
// (async () => {
//     const weChatApi = new WeChat()
//     const data = weChatApi.fetchTicket();
//     console.log(data)
// })()

module.exports = WeChat